package com.mspbots.rule.scheduled.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mspbots.api.config.ApiProperties;
import com.mspbots.cw.request.MessagesDTO;
import com.mspbots.cw.request.TenantDTO;
import com.mspbots.cw.request.TenantUserConfigurationDTO;
import com.mspbots.dto.enums.Configuration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.mspbots.rule.config.RuleConfiguration.REDIS_KEY_PREFIX_SYSTEM;
import static com.mspbots.rule.config.RuleConfiguration.REDIS_KEY_PREFIX_TENANT;


/**
 * com.mspbots.rule.scheduled.service.MessagesService
 *
 * @author Jun Zhou
 * @description
 * @date 13:58 2019/6/18
 **/
@Slf4j
@Component
public class MessagesSendService {

    private static final String MESSAGES_SWITCH_ON = "on";
    public MessagesService messagesApi;
    protected ApiProperties apiProperties;
    private TenantUserMappingService tenantUserMappingTeamUserService;
    private TenantUserConfigurationService tenantUserConfigurationService;
    private SystemConfigurationService systemConfigurationService;
    private TenantConfigurationService tenantConfigurationService;
    private Map<Long, String[]> messageForwardMap;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    public MessagesSendService(TenantConfigurationService tenantConfigurationService,
                               TenantUserMappingService tenantUserMappingTeamUserService,
                               TenantUserConfigurationService tenantUserConfigurationService,
                               SystemConfigurationService systemConfigurationService,
                               MessagesService messagesApi, ApiProperties apiProperties
    ) {
        this.tenantUserMappingTeamUserService = tenantUserMappingTeamUserService;
        this.tenantUserConfigurationService = tenantUserConfigurationService;
        this.systemConfigurationService = systemConfigurationService;
        this.tenantConfigurationService = tenantConfigurationService;
        this.messagesApi = messagesApi;
        this.apiProperties = apiProperties;


    }

    private void setForward() {
        messageForwardMap = new HashMap<>();
        String systemForwardIds = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_SYSTEM + Configuration.MESSAGES_FORWARD.getKeyword());
        List<TenantDTO> tenantDTOS = objectMapper.convertValue(redisTemplate.opsForList().range(REDIS_KEY_PREFIX_TENANT + "tenants", 0, -1), new TypeReference<List<TenantDTO>>() {
        });

        messageForwardMap.put(Long.valueOf(0), getForwardUserIds(systemForwardIds));
        for (TenantDTO dto : tenantDTOS) {
            String tenantForwardIds = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_TENANT + dto.getId() + ":" + Configuration.MESSAGES_FORWARD.getKeyword());
            messageForwardMap.put(dto.getId(), getForwardUserIds(tenantForwardIds));
        }
    }

    @Async
    public void sendToTeams(MessagesDTO messagesDTO) {
        Map<String, Object> params = new HashMap<>(16);
        params.put("tenantId", messagesDTO.getTenantId());
        params.put("tenantUserId", messagesDTO.getUserId());
        TenantUserConfigurationDTO tenantUserConfiguration = tenantUserConfigurationService.findByKeyword(params, Configuration.MESSAGES_SWITCH);
        if (tenantUserConfiguration == null || MESSAGES_SWITCH_ON.equalsIgnoreCase(tenantUserConfiguration.getKeywordValue())) {
            if (!StringUtils.isEmpty(messagesDTO.getTeamsUserId())) {
                //messagesDTO.setMessage(messagesDTO.getMessage() + (suffixBugReport(messagesDTO,"send")));
                Future<String> resultStr = messagesApi.sendToTeams(messagesDTO, "send");
                try {
                    if ("1".equals(resultStr.get())) {
                        messagesDTO.setStatus("Received");
                        messagesApi.updateStatus(messagesDTO);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }


    public void sendToTeams(List<MessagesDTO> messagesList) {
        Map<Long, List<MessagesDTO>> messagesGroupByUserId = messagesList.stream().collect(Collectors.groupingBy(MessagesDTO::getUserId));
        Iterator<Map.Entry<Long, List<MessagesDTO>>> iterator = messagesGroupByUserId.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, List<MessagesDTO>> record = iterator.next();
            Long userId = record.getKey();
            List<MessagesDTO> userMessages = record.getValue();
            Map<String, Object> params = new HashMap<>(16);
            params.put("tenantId", userMessages.get(0).getTenantId());
            params.put("tenantUserId", userId);
            TenantUserConfigurationDTO tenantUserConfiguration = tenantUserConfigurationService.findByKeyword(params, Configuration.MESSAGES_SWITCH);
            if (tenantUserConfiguration == null || MESSAGES_SWITCH_ON.equalsIgnoreCase(tenantUserConfiguration.getKeywordValue())) {
                StringBuilder newMessage = new StringBuilder();
                int msgSize = userMessages.size() > 5 ? 5 : userMessages.size();
                List<MessagesDTO> updateList = new ArrayList<>();
                for (int i = 0; i < msgSize; i++) {
                    newMessage.append(userMessages.get(i).getMessage())
                            .append(suffixBugReport(userMessages.get(i), "send")).append("<br><br>");
                    MessagesDTO updateItem = new MessagesDTO();
                    updateItem.setId(userMessages.get(i).getId());
                    updateItem.setStatus("Received");
                    updateItem.setSentTime(LocalDateTime.now());
                    updateList.add(updateItem);
                }


                MessagesDTO sendDto = new MessagesDTO();
                sendDto.setId(userMessages.get(0).getId());
                sendDto.setTeamsUserId(userMessages.get(0).getTeamsUserId());
                sendDto.setMessage(newMessage.toString());
                Future<String> resultStr = messagesApi.sendToTeams(sendDto, "send");

                log.debug("send message [{}] to {} : {} ", sendDto.getId(), sendDto.getTeamsUserId(), resultStr);
                try {
                    if ("1".equals(resultStr.get())) {
                        if (updateList.size() > 1) {
                            messagesApi.batchUpdateStatus(updateList);
                        } else {
                            sendDto.setStatus("Received");
                            messagesApi.updateStatus(sendDto);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                log.info("user [{}] switch is off [{}]  ", tenantUserConfiguration.getTenantUserId(), tenantUserConfiguration.getId());
            }

        }


    }


    public void sendForward(MessagesDTO messages) {

        messages.setMessage(messages.getMessage() + suffixBugReport(messages, "sendForward"));
        boolean update = false;
        String systemForwardIds = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_SYSTEM + Configuration.MESSAGES_FORWARD.getKeyword());

        // forward all message based on system configuration
        String[] forwardSystemUsers = getForwardUserIds(systemForwardIds);
        for (String user : forwardSystemUsers) {
            if (!StringUtils.isEmpty(user)) {
                messages.setTeamsUserId(user);
                Future<String> resultStr = messagesApi.sendToTeams(messages, "forwardSys");
                try {
                    if ("1".equalsIgnoreCase(resultStr.get())) {
                        update = true;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
        String tenantForwardIds = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_TENANT + messages.getTenantId() + ":" + Configuration.MESSAGES_FORWARD.getKeyword());

        // forward tenant message base on tenant configuration
        if (!StringUtils.isEmpty(tenantForwardIds)) {
            String[] forwardTenantUsers = getForwardUserIds(tenantForwardIds);
            for (String user : forwardTenantUsers) {
                if (!StringUtils.isEmpty(user)) {
                    messages.setTeamsUserId(user);
//                    log.info("forward {} tenant to {}",messages.getId(), user);
                    Future<String> resultStr = messagesApi.sendToTeams(messages, "forwardTenant");
                    try {
                        if ("1".equalsIgnoreCase(resultStr.get())) {
                            update = true;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        if (update) {
            MessagesDTO updateMessage = new MessagesDTO();
            updateMessage.setId(messages.getId());
            updateMessage.setForwardStatus("Received");
            messagesApi.updateStatus(updateMessage);
        }
    }


    public void sendForward(List<MessagesDTO> messagesList) {
        messagesList.parallelStream().forEach(messages -> sendForward(messages));
//        for (MessagesDTO messages : messagesList) {
//            sendForward(messages);
//        }
    }

    public String suffixBugReport(MessagesDTO messages, String from) {
        StringBuilder sb = new StringBuilder().append("timeEntryId=").append(messages.getTimeEntryId())
                .append("&messageId=").append(messages.getId())
                .append("&tenantId=").append(messages.getTenantId())
                .append("&tenantUserId=").append(messages.getUserId())
                .append("&from=").append(from);
        return "&nbsp;<span style='color:#999d9c;font-size:10px;'>--[<a href='" + apiProperties.getPortalUrl() + "/bug?params=" +
                Base64Utils.encodeToString(sb.toString().getBytes(StandardCharsets.UTF_8))
                + "' >Report an error about this message</a>]</span>";
    }

    private List<MessagesDTO> getMessagesList(Long tenantId, String type) {
        Map<String, Object> messagesParams = new HashMap<>(16);
        messagesParams.put("tenantId", tenantId);
        messagesParams.put(type, "Ready");
        messagesParams.put("expireDate", LocalDateTime.now());
        return messagesApi.findList(messagesParams);
    }

    private String[] getForwardUserIds(String strForward) {
        if (StringUtils.isEmpty(strForward)) {
            return new String[0];
        }

        return strForward.split(",");
    }
}
